﻿using Common;
using SFJDService.EventHandle;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace SFJDService
{
    class FileSend
    {
        internal static List<ClassTransCSInfo> tasks = new List<ClassTransCSInfo>(3);
        static int maxLength = 1400; //文件发送时的缓冲区大小
        //static int maxLength = 65500;
        Socket socketClient;

        public FileSend()
        {
            if (Runtime.onSending)
            {
                return;
            }
            else
            {
				Runtime.onSending = true;
                Connect(tasks[0].IPRecive);
            }
        }

        #region 连接服务器
        private void Connect(string ip)
        {
            Runtime.onSending = true;
            IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse(ip), Runtime.portFile);
            //创建服务端负责监听的套接字，参数（使用IPV4协议，使用流式连接，使用TCO协议传输数据）
            socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                socketClient.Connect(endpoint);
                Runtime.Printf(socketClient.RemoteEndPoint + "文件端口连接成功");
                //Thread.Sleep(100);//等待xml写入
                bool hasXml = false;//等待xml文件写完
                for (int i = 0; i < 10; i++)
                {
                    if (Runtime.xmlUpload.isThereGuid(tasks[0].TransGuid))
                    {
                        hasXml = true;
                        break;
                    }
                    else
                    {
                        Thread.Sleep(200 * i);
                    }
                }
                if (!hasXml)
                {
                    throw new System.Exception("错误：读取xml文档未找到指定任务 " + this.GetType());
                }

                ClassTransportInfo transInfo = null;
                Runtime.Printf("         FileSend开始读取XML");
                while((transInfo = Runtime.xmlUpload.GetTransInfo(tasks[0].TransGuid)).RootPath == null) { }
                Runtime.Printf("         FileSend读取XML完成");
                //while ((transInfo = new XmlTransport(Common.XmlHandle.TransportType.Upload, Runtime.pathTemp).GetTransInfo(tasks[0].TransGuid)).RootPath == null) { }
                foreach (ClassFileInfo file in transInfo.Files)
                {
                    string fileFullPath = transInfo.RootPath + file.RelativePath;//获取文件的完整路径

                    FileStream fs = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read);
                    try
                    {
                        long fileLen = fs.Length;                        // 文件长度
                        long leftLen = fileLen;                            // 未读取部分
                        int readLen = 0;                                // 已读取部分
                        byte[] buffer = null;
                        int type = 0;

                        if (fileLen <= maxLength)
                        {
                            buffer = new byte[fileLen];
                            readLen = fs.Read(buffer, 0, (int)fileLen);
                            SendData(socketClient, buffer, -1, 0);
                            //Send(socketClient, buffer, 0);
                        }
                        else
                        {
                            while (leftLen != 0)
                            {
                                if (leftLen < maxLength)
                                {
                                    buffer = new byte[leftLen];
                                    readLen = fs.Read(buffer, 0, Convert.ToInt32(leftLen));
                                }
                                else
                                {
                                    buffer = new byte[maxLength];
                                    readLen = fs.Read(buffer, 0, maxLength);
                                }
                                if ((SendData(socketClient, buffer, 10, type)) < 0)
                                {
                                    break;
                                }
                                //Send(socketClient, buffer, type);
                                leftLen -= readLen;
                            }
                        }
                    }
                    catch
                    {
                        throw;
                    }
                    finally
                    {
                        fs.Flush();
                        fs.Close();
                    }
                }
                Runtime.Printf("文件发送成功。。");
            }
            catch
            {
                Runtime.Printf("文件发送失败。。");
                throw;
            }
            finally
            {
                socketClient.Dispose();
                socketClient.Close();
                Task0Completed();//传送列表task中的第一个任务完成后的操作
            }
        }
        #endregion

        private static void Send(Socket socket, byte[] buffer, int type)
        {
            try
            {
                int left = buffer.Length;
                int sndLen = 0;
                while (true)
                {
                    sndLen = socket.Send(buffer, sndLen, left, SocketFlags.None);
                    left -= sndLen;
                    if (left == 0)
                    {                                        // 数据已经全部发送
                        break;
                    }
                    else
                    {
                        if (sndLen > 0)
                        {                                    // 数据部分已经被发送
                            continue;
                        }
                        else
                        {                                                // 发送数据发生错误
                            throw new Exception("发送数据发生错误");
                        }
                    }
                }
            }
            catch
            {
                throw new Exception();
            }
            finally
            {
                Runtime.onSending = false;
            }
        }

        /// <summary>
        /// 向远程主机发送数据
        /// </summary>
        /// <param name="socket">要发送数据且已经连接到远程主机的 Socket</param>
        /// <param name="buffer">待发送的数据</param>
        /// <param name="outTime">发送数据的超时时间，以秒为单位</param>
        /// <returns>0:发送数据成功；-1:超时；-2:发送数据出现错误；-3:发送数据时出现异常</returns>
        /// <remarks >
        /// 当 outTime 指定为-1时，将一直等待直到有数据需要发送
        /// </remarks>
        public static int SendData(Socket socket, byte[] buffer, int outTime, int type)
        {
            if (socket == null || socket.Connected == false)
            {
                throw new ArgumentException("参数socket 为null，或者未连接到远程计算机");
            }
            if (buffer == null || buffer.Length == 0)
            {
                throw new ArgumentException("参数buffer 为null ,或者长度为 0");
            }
            int flag = 0;
            try
            {
                int left = buffer.Length;
                int sndLen = 0;
                while (true)
                {
                    if ((socket.Poll(outTime * 1000, SelectMode.SelectRead) == true))
                    {        // 收集了足够多的传出数据后开始发送
                        
                        string bu = "";
                        foreach (byte bte in buffer)
                        {
                            bu += bte;
                        }

                        sndLen = socket.Send(buffer, sndLen, left, SocketFlags.None);
                        left -= sndLen;
                        if (left == 0)
                        {                                        // 数据已经全部发送
                            flag = 0;
                            break;
                        }
                        else
                        {
                            if (sndLen > 0)
                            {                                    // 数据部分已经被发送
                                continue;
                            }
                            else
                            {                                                // 发送数据发生错误
                                flag = -2;
                                Runtime.Printf("FileSend    发送数据发生错误");
                                break;
                            }
                        }
                    }
                    else
                    {                                                        // 超时退出
                        flag = -1;
                        Runtime.Printf("FileSend    超时退出");
                        break;
                    }
                }
            }
            catch 
            {
                flag = -3;
            }
            finally
            {
                Runtime.onSending = false;
            }
            return flag;
        }

        private void Task0Completed()
        {
            var eventData = new SCFileSendFinishData() { transInfo = tasks[0] };
            EventBus.instance.Trigger<SCFileSendFinishData>(eventData);
            //new XmlTransport(Common.XmlHandle.TransportType.Upload, Runtime.pathTemp).RemoveByGuid(tasks[0].TransGuid);
            Runtime.xmlUpload.RemoveByGuid(tasks[0].TransGuid);
            tasks.RemoveAt(0);
            Runtime.onSending = false;
        }
    }
}
